docs(deploy): by-reference deploys, sealed credentials, and server-side SSH keygen (v5.2.3 / v5.2.4) - #636
Conversation
Splits the shipped half of #599 out so it can merge on its own. Everything here documents behavior in **v5.2.3** — `git tag --contains` on harper#1850's and harper#1851's merge commits returns v5.2.3 and v5.2.4 — while #599 is gated on harper#1849, still a draft. Accurate docs for a shipped feature should not wait on unshipped work. Carries the corrected text, not #599's original: the corrections that lived in #617 are folded in here, so there is no window where the published page describes the superseded parameter form. - **Deploying by Reference** — `harper deploy by_ref=true`, `ref=`, `credential=true`. A reference pins to a resolved SHA: refs resolve from the local checkout, then from the remote when it is absent (a shallow CI clone usually has neither), and the deploy fails closed if neither can name a commit, because peers resolve the package independently. A ref must also name something a clone can fetch — `refs/heads/*` or `refs/tags/*` — so `refs/pull/123/head` is rejected up front even where the local checkout resolves it. A pinned SHA fixes the source revision, not the built artifact. - **`credential=true`** derives the host from the package, so the credential always matches the clone it authenticates; an explicitly named host that does not match is rejected rather than silently unused. - **GitHub Actions behavior** — the unpushed-commit check is skipped there (the runner's checkout is not a branch `git branch -r --contains` can see) while the dirty-tree warning still applies, and a `pull_request` run deploys the PR's head commit rather than the merge commit the runner checks out. - **Provisioning a Deploy Credential** — `harper deploy setup=true`, the client-side sealing flow, the two providers it supports, and that it needs super_user because it calls `get_secrets_public_key` and `set_secret`. - `reference/security/secrets.md` points its private-source section at the CLI flow, and `5.2.md` gains the two release-note entries. The `revert_component` cross-reference from the credential section is deliberately left on #599: `revert_component` is unshipped, and the build caught the dangling anchor when it came across.
Same reasoning as the by_ref content: harper-pro#594 merged 2026-08-20 and `git tag --contains` puts it in **v5.2.4**, so it is shipped and should not wait on harper#1849. - `generate: true` mints an ed25519 keypair on the node and returns only the public half, so a deploy key's private half never travels in a request body, shell history, or CI log. Generation is in-process (`node:crypto`), needing no `ssh-keygen` binary on the host. - `public_key` comes back only on the generating call — Harper does not retain it — so the recovery path is delete-and-regenerate, since `update_ssh_key` cannot mint. - The encryption-at-rest claim is qualified rather than absolute. `sealSSHKey` falls back to storing and replicating the private key in **plaintext** with only a WARN when no secret custody is registered, and that fallback is deliberate — SSH keys predate custody. So it is a property of the deployment's configuration, not of the operation, which matters most for `generate: true` because that reads as though the key could never be exposed. Custody is present by default, and the note says so rather than implying the risk is likely. Also restores the 5.2.4 release-note entry, which I dropped when I took main's `5.2.md` wholesale during the #599 merge — the same whole-file resolution hazard that cost content once already in this session. Verifying the file matched main confirmed the take succeeded but said nothing about what #599 uniquely added.
There was a problem hiding this comment.
Code Review
This pull request updates the Harper documentation and release notes to cover new features, including deploying by git reference, provisioning sealed deploy credentials with client-side encryption, and server-side SSH key generation. The review feedback suggests resolving a duplicate configuration header in the release notes, clarifying ambiguous phrasing regarding when a reference is sent to the cluster, and using the standard <VersionBadge> component in the secrets documentation for consistency.
🚀 Preview DeploymentYour preview deployment is ready! 🔗 Preview URL: https://preview.harper-documentation.harperfabric.com/pr-636 This preview will update automatically when you push new commits. |
Removes what #636 now owns, so this PR is purely surface gated on harper#1849 (draft) or unreleased: - `reference/components/applications.md` — Deploying by Reference and Provisioning a Deploy Credential (both v5.2.3). The page returns to Package Sources followed by Dependency Management. - `reference/operations-api/operations.md` — the `add_ssh_key` section reverts to main's, handing the `generate` subsection and its custody caveat (v5.2.4) over. - `reference/security/secrets.md` — the `deploy setup=true` pointer. One point was relocated rather than dropped. The credential section carried a note that rolling back needs no credential, which is a fact about `revert_component` rather than about provisioning, and `revert_component` stays here. It now sits in that operation's own docs, phrased for why it matters: a revert re-fetches nothing, so it still works when the token or deploy key that installed the current version has expired or been revoked — which is often the situation you are in when you need to roll back. What remains is two-phase deploy, `revert_component`, the deployment lifecycle and retention, the CLI stage/activate/revert rows, and OIDC.
Two of gemini's three findings on #636. The duplicate `## Configuration` in `5.2.md` is mine: extracting the two 5.2.3 release-note entries by line range swept up the following section heading with them, so the merged file carried it twice. Removed. Extracting by heading boundary rather than line number would have avoided it — the same lesson as the `add_ssh_key` extraction earlier, where an off-by-one line range grabbed a neighbouring section. "Resolved to a commit SHA before it ships" is genuinely ambiguous — "ships" reads as a software release in a paragraph that is otherwise about git refs. Now "before it is sent to the cluster", which is what actually happens. Declining the third: it asks for `<VersionBadge version="v5.2.3" />` in place of the inline `(v5.2.3+)` in `secrets.md`. That text sits mid-sentence in prose, and CONTRIBUTING.md is explicit — "using the component mid-sentence is awkward. Reserve `<VersionBadge>` for standalone placement after headings." The exact patch version it also asks for is already there.
🚀 Preview DeploymentYour preview deployment is ready! 🔗 Preview URL: https://preview.harper-documentation.harperfabric.com/pr-636 This preview will update automatically when you push new commits. |
Per @cb1kenobi: the flow also calls `grant_secret` (bin/deploySetup.ts:130, step 5 of its header comment), which I omitted. It is equally SU-only (utility/operation_authorization.ts:345), so the guidance was right and only the list was short. Worth noting the omission is not random — my own text three paragraphs above describes the flow as five steps including grant_secret, so the call list contradicted the flow description on the same page.
🚀 Preview DeploymentYour preview deployment is ready! 🔗 Preview URL: https://preview.harper-documentation.harperfabric.com/pr-636 This preview will update automatically when you push new commits. |
|
Reviewed Re-review scope: 1 new commit since The Nit ( Everything else on the page is untouched by this push, so it wasn't re-verified in this pass (already confirmed clean at — |
Two of gemini's three findings on #636. The duplicate `## Configuration` in `5.2.md` is mine: extracting the two 5.2.3 release-note entries by line range swept up the following section heading with them, so the merged file carried it twice. Removed. Extracting by heading boundary rather than line number would have avoided it — the same lesson as the `add_ssh_key` extraction earlier, where an off-by-one line range grabbed a neighbouring section. "Resolved to a commit SHA before it ships" is genuinely ambiguous — "ships" reads as a software release in a paragraph that is otherwise about git refs. Now "before it is sent to the cluster", which is what actually happens. Declining the third: it asks for `<VersionBadge version="v5.2.3" />` in place of the inline `(v5.2.3+)` in `secrets.md`. That text sits mid-sentence in prose, and CONTRIBUTING.md is explicit — "using the component mid-sentence is awkward. Reserve `<VersionBadge>` for standalone placement after headings." The exact patch version it also asks for is already there.
🧹 Preview CleanupThe preview deployment for this PR has been removed. |
Documents the private-source deploy workflow that has already shipped: by-reference deploys and sealed deploy credentials in v5.2.3, and
add_ssh_key generatein v5.2.4.Split out of #599, which remains gated on harper#1849 — still a draft. There is no reason for docs describing shipped behavior to wait on unshipped work, and this content had been blocked that way for weeks.
Supersedes #617, whose corrections are folded in here rather than layered on top, so there is no window where the published page describes a parameter form the CLI rejects.
What shipped, and where it landed
deploy by_ref=true/ref=/credential=truedeploy setup=trueadd_ssh_key generate: trueEach verified with
git tag --containson the merge commit rather than from a branch'spackage.json— the latter is what previously left this content badgedv5.2.0for a month.For the human reviewer
credentialparameter form changed, and the old docs were wrong. docs(deploy): two-phase deploy, revert, by-reference deploys, and OIDC trusted publishing #599's original text saidcredentialtakes a git host (credential=github.com).resolveCredentialHostnow rejects an explicitly named host that does not match the package's, with an error telling you to usecredential=true. Publishing the old form would have documented a rejected invocation. This is the main reason the split is worth the churn rather than waiting.sealSSHKeystill falls back to storing and replicating the private key in plaintext with only a WARN when no secret custody is registered, and that fallback is deliberate — SSH keys predate custody. So the docs say encryption at rest is a property of your configuration, not of the operation. That reads as a weaker promise than we might want to make; it is the accurate one. Custody is present by default and the note says so.revert_componentcross-reference was deliberately left behind. The credential section previously pointed atrevert_componentfor the no-credential rollback path. That operation is unshipped, so the reference stays on docs(deploy): two-phase deploy, revert, by-reference deploys, and OIDC trusted publishing #599 — the build caught it as a dangling anchor when it came across, which is a good argument for the split.Verification
Docs-only; per
AGENTS.mdthe build is the end-to-end check. At head:npm run format:checkclean,npm run buildsucceeds. The build reports two broken anchors, both pre-existing onmainand neither in a file this PR touches — confirmed by buildingmainwith these changes stashed.Behavior verified against harper v5.2.4 source, not against the PRs that introduced it:
credential=truederives the package host; a mismatched host is rejectedresolveCredentialHostresolveExplicitRefrefs/heads/*andrefs/tags/*are fetchableassertCloneableRefNamespacebin/cliOperations.ts(GITHUB_SHAguard)pull_requestrun deploys the PR head, not the merge commitresolveActionsPullRequestHeaddeploy setup=truesupports exactlygithubandnpm, and needs super_userbin/deploySetup.ts,utility/operation_authorization.tssecurity/sshKeyGeneration.ts,sealSSHKeyNotes
5.2.mdwith each entry labelled by the patch that shipped it, since this repo keeps one page per minor and points patches at GitHub releases. A patch-shipped feature is otherwise undiscoverable from the docs.Description drafted by Claude Code (Opus 5).